use crate::alloc::sync::Arc;
use crate::thread::Thread;
use core::mem;
use rtt_kernel_mutex::KMutex;

pub enum CurrentThType {
    Null,
    PrepareSchedule(Arc<KMutex<usize>>),
    Thread(Thread),
}

impl CurrentThType {
    pub fn is_thread(&self) -> bool {
        match self {
            CurrentThType::Thread(_) => true,
            _ => false,
        }
    }

    pub fn get_thread_set_sp(&mut self) -> Option<Thread> {
        match self {
            CurrentThType::Null => None,
            CurrentThType::PrepareSchedule(_) => {
                panic!()
            }
            CurrentThType::Thread(a) => {
                let mut th = CurrentThType::PrepareSchedule(a.get_sp().clone());
                mem::swap(&mut th, self);
                if let CurrentThType::Thread(ret) = th {
                    Some(ret)
                } else {
                    panic!()
                }
            }
        }
    }

    pub fn thread_update_thread(&mut self, th: Thread) -> Thread {
        if !self.is_thread() {
            panic!()
        };

        let mut new = CurrentThType::Thread(th);
        mem::swap(&mut new, self);

        if let CurrentThType::Thread(a) = new {
            a
        } else {
            panic!()
        }
    }

    pub fn thread_take_thread(&mut self) -> Thread {
        if !self.is_thread() {
            panic!()
        };

        let mut new = CurrentThType::Null;
        mem::swap(&mut new, self);

        if let CurrentThType::Thread(a) = new {
            a
        } else {
            panic!()
        }
    }

    pub fn thread_get_thread(&self) -> &Thread {
        if self.is_thread() {
            if let CurrentThType::Thread(a) = self {
                a
            } else {
                panic!()
            }
        } else {
            panic!()
        }
    }

    pub fn is_sp(&self) -> bool {
        match self {
            CurrentThType::PrepareSchedule(_) => true,
            _ => false,
        }
    }

    pub fn sp_set_thread(&mut self, th: Thread) -> Arc<KMutex<usize>> {
        if !self.is_sp() {
            panic!()
        };

        let mut new = CurrentThType::Thread(th);
        mem::swap(&mut new, self);

        if let CurrentThType::PrepareSchedule(a) = new {
            a
        } else {
            panic!()
        }
    }

    pub fn is_null(&self) -> bool {
        match self {
            CurrentThType::Null => true,
            _ => false,
        }
    }

    pub fn null_set_thread(&mut self, th: Thread) {
        if !self.is_null() {
            panic!()
        };

        let mut new = CurrentThType::Thread(th);
        mem::swap(&mut new, self);
    }
}
